// 引入 Koa 构造函数
const Koa = require('koa');
// 创建 Koa 实例
const app = new Koa();

// 引入 KoaRouter 构造函数
const KoaRouter = require('koa-router');
// 根据构造函数，创建路由实例
const router = new KoaRouter();

// 引入解析请求体数据的中间件
const bodyparser = require('koa-bodyparser');
// 启用 bodyParser 中间件
app.use(bodyparser());

// 汇总参数到 params
const paramsMiddleware = require('./middleware/params');
app.use(paramsMiddleware);

// 引入执行 mysql 语句的函数
const { query } = require('./util');

// 添加用户接口
router.post('/users', async (ctx) => {
    // 获取请求参数
    let { username, password, mobile, email, age, sex } = ctx.request.body;

    // ===============> 校验参数
    // 1、非空校验
    if (!username || !password || !mobile || !email || !age || !sex) {
        ctx.body = {
            code: 400,
            message: '参数不能为空',
        };
        return;
    }
    // 2、参数值的格式校验
    // 用户名格式校验
    if (!/^[a-zA-Z0-9_]{5,20}$/.test(username)) {
        ctx.body = {
            code: 400,
            message: '用户名必须是 5 ~ 20 位的字母数字下划线组合',
        };
        return;
    }

    // 密码格式校验
    if (!/^[\w]{6,20}$/.test(password)) {
        ctx.body = {
            code: 400,
            message: '密码必须是 6 ~ 20 位',
        };
        return;
    }

    // 手机号格式校验 => 13811065680
    if (!/^1[35789]\d{9}$/.test(mobile)) {
        ctx.body = {
            code: 400,
            message: '手机号格式不正确',
        };
        return;
    }

    // 邮箱格式校验 => 531804271@qq.com
    if (!/^\w+@\w+\.com$/.test(email)) {
        ctx.body = {
            code: 400,
            message: '邮箱格式不正确',
        };
        return;
    }

    // 年龄格式校验 is not a number
    if (isNaN(age)) {
        ctx.body = {
            code: 400,
            message: '年龄格式不正确',
        };
        return;
    }

    // 转换年龄的格式
    age = parseInt(age);

    if (age < 0 || age > 150) {
        ctx.body = {
            code: 400,
            message: '不合法的年龄值',
        };
        return;
    }

    // 用户名唯一性校验，用户名不能重复
    try {
        // await 只能用在返回 promise 的方法上
        // await 只能在 async 函数中使用
        // 在 Koa2 中，处理异步编程，使用的都是 async / await
        let res = await query('select * from user where username = ?', [
            username,
        ]);

        // 已存在该用户
        if (res.length > 0) {
            ctx.body = {
                code: 403,
                message: '该用户已存在，不允许重复创建',
            };
            return;
        }

        // 将信息保存到数据库 insert into
        res = await query(
            'insert into user (username, password, mobile, email, age, sex) values (?, ?, ?, ?, ?, ?)',
            [username, password, mobile, email, age, sex],
        );

        // insert into 返回的是一个 OkPacket 对象
        // 判断是否插入成功
        if (res.affectedRows !== 1) {
            ctx.body = {
                code: 500,
                message: '用户创建失败，请稍后再试。',
            };
            return;
        }

        // 用户添加成功
        ctx.body = {
            code: 201,
            message: '用户添加成功',
        };
    } catch (error) {
        ctx.body = {
            code: 500,
            message: '服务器异常，请联系管理员，联系方式：13023281932',
        };
    }
});

// 获取用户列表接口
router.get('/users', async (ctx) => {
    // 获取请求参数
    // console.log('params', ctx.params);
    const { pagenum = 1, pagesize = 10 } = ctx.params;
    // 需要计算总的页数
    const countArr = await query('select count(*) as count from user');
    // console.log('countArr', countArr);
    // 计算分页偏移量
    const startIndex = (pagenum - 1) * pagesize;
    // 发送 SQL 语句，获取数据库中的数据
    const list = await query(
        'select id, username, mobile, email, age, sex from user limit ?, ?',
        [
            startIndex,
            // 前台传入的都是字符串，而分页参数必须转成数字类型，字符串类型会报错
            parseInt(pagesize),
        ],
    );
    // 返回从数据库中，查询出来的数据
    ctx.body = {
        code: 200,
        data: {
            total: countArr[0]['count'],
            list,
        },
        message: '获取用户列表成功',
    };
});

// 修改用户信息接口
router.put('/users/:id', async (ctx) => {
    // 获取参数
    let { id, password, mobile, email, sex, age } = ctx.params;

    // 拼装 sql
    let sql = 'update user set';
    let params = [];

    // 判断，有就修改，没有就不修改
    if (password) {
        if (!/^[\w]{6,20}$/.test(password)) {
            ctx.body = {
                code: 400,
                message: '密码必须是 6 ~ 20 位',
            };
            return;
        }
        sql += ' password = ?,';
        params.push(password);
    }

    if (mobile) {
        if (!/^1[35789]\d{9}$/.test(mobile)) {
            ctx.body = {
                code: 400,
                message: '手机号格式不正确',
            };
            return;
        }
        sql += ' mobile = ?,';
        params.push(mobile);
    }

    if (email) {
        if (!/^\w+@\w+\.com$/.test(email)) {
            ctx.body = {
                code: 400,
                message: '邮箱格式不正确',
            };
            return;
        }
        sql += ' email = ?,';
        params.push(email);
    }

    if (sex) {
        sql += ' sex = ?,';
        params.push(sex);
    }

    if (age) {
        if (isNaN(age)) {
            ctx.body = {
                code: 400,
                message: '年龄格式不正确',
            };
            return;
        }

        // 转换年龄的格式
        age = parseInt(age);

        if (age < 0 || age > 150) {
            ctx.body = {
                code: 400,
                message: '不合法的年龄值',
            };
            return;
        }

        sql += ' age = ?,';
        params.push(age);
    }

    sql = sql.substring(-1, sql.length - 1);

    sql += ' where id = ?';
    params.push(id);

    const res = await query(sql, params);

    if (res.affectedRows !== 1) {
        ctx.body = {
            code: 500,
            message: '用户信息修改失败，请稍后再试。',
        };
        return;
    }

    ctx.body = {
        code: 200,
        message: '用户信息修改成功',
    };
});

// 修改密码
router.put('/users/:id/password', async (ctx) => {
    // 获取参数
    const { id, newpassword } = ctx.params;

    // 先查询数据库，是否存在该用户
    let res = await query('select * from user where id = ?', [id]);
    if (res.length === 0) {
        ctx.body = {
            code: 404,
            message: '用户不存在',
        };
        return;
    }

    // 获取该用户
    const user = res[0];

    // 新密码不能和旧密码相同
    if (user.password === newpassword) {
        ctx.body = {
            code: 403,
            message: '新密码不能和原有密码相等',
        };
        return;
    }

    // 修改数据库中的旧密码
    res = await query('update user set password = ? where id = ?', [
        newpassword,
        id,
    ]);
    if (res.affectedRows !== 1) {
        ctx.body = {
            code: 500,
            message: '用户密码修改失败，请稍后再试。',
        };
        return;
    }

    ctx.body = {
        code: 200,
        message: '用户密码修改成功',
    };
});

// 删除用户
router.delete('/users/:id', async (ctx) => {
    const { id } = ctx.params;
    // 使用 query 方法，向数据库发送删除 SQL 语句
    const res = await query('delete from user where id = ?', [id]);
    // 判断是否删除成功
    if (res.affectedRows !== 1) {
        ctx.body = {
            code: 500,
            message: '删除用户失败',
        };
        return;
    }
    // 走到这里，说明删除成功了，返回成功响应给前端
    ctx.body = {
        code: 204,
        message: '删除用户成功',
    };
});

// 加载路由
app.use(router.routes());

// 监听端口，启动 web 服务
app.listen(3000, () => {
    console.log('Koa server listening at http://localhost:3000');
});
